
#include "shader.h"
#include "window.h"
#include "globals.h"
#include "fbo.h"
#include <map>

ADSShader shader;
DMShader dm_shader;

Window window(1280, 800, &shader, &dm_shader);

float PI_over_2 = 3.14159265f / 2.0f;
float PI = 3.14159265f;

/*	These are simple functions which drive the creation of various surfaces of revolution.
*/

float CosWave(float t)
{
	float f = t;
	t = t * 2.0f * PI;
	float radius = cos(t) / 4.0f + 0.75f;
	return radius * f;
}

float HourGlass(float t)
{
	t = (2 * t - 1.0f) * PI_over_2;
	float radius = fabs(sin(t)) / 4.0f + 0.5f;
	return radius;
}

float Cone(float t)
{
	return t;
}

float InverseCone(float t)
{
	return 1.0f - t;
}

float TestCone(float t)
{
	return t / 2.0f;
}

float Cylinder(float t)
{
	return 0.5f;
}

/*	This method of creating a sphere does not sample the poles sufficiently densely. Therefore,
	a different means of sampling t should be used.
*/

float Sphere(float t)
{


	t = t - 0.5f;
	return sqrt(0.25f - t * t);
}

#if 1
float Bottle(float t)
{

	if (t < .05){
		return .06;
	}

	else if (t < .15) {

		t = t * PI;
		float radius = tan(t + .2) / 4.1f + .60f; 
		return radius - .6;

	}

	else {return .2f;}
	
	/*if (t < .05){
		return .06;
	}

	else if (t < .2) { //.2

		t = t * PI;
		float radius = sin(t) / 4.1f + .62f;
		return radius - .6;

	} 

	else {return .2f;}*/
}
#endif

float Squiggle(float t)
{
	return t > 0.5f ? (t > 0.75f ? sin(t + PI) : cos(t + PI)) : sin(t - PI);
}


void DisplayFunc()
{
	if (window.drewDestinationSet)
	{
		window.destinationSet = false;

		//set source and destination equal
		window.UpdateSource(glm::vec2(0,0));
		window.UpdateDestination(glm::vec2(0,0));
	}
	glViewport(0, 0, window.width, window.height);
	glClearColor(0, 0, 0, 1);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);

	//Determine wireframe
	glPolygonMode(GL_FRONT_AND_BACK, window.wireframe ? GL_LINE : GL_FILL);
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_LIGHTING);

	switch (window.mode)
	{
	case ORANGE_BEAUTY:
		window.DrawOrange();
		break;
	case BOTTLE_BEAUTY:
		window.DrawBottle();
		break;
	case PICTURE_FRAME_BEAUTY:
		window.DrawBackGround();
		break;
	case STILL_LIFE:
		window.DrawScene();
		break;
	}
	glutSwapBuffers();
}

void TimerFunc(int period)
{
	glutTimerFunc((unsigned int) period, TimerFunc, period);

	if (window.window_handle != -1)
		glutPostRedisplay();
}

void ReshapeFunc(int w, int h)
{
	if (h == 0)
		return;
	window.width = w;
	window.height = h;
}

void SpecialFunc(int c, int x, int y)
{
	switch (c)
	{

	}
}

void SwitchModes()
{
	switch (window.mode)
	{
		case ORANGE_BEAUTY:
			window.mode = BOTTLE_BEAUTY;
			break;
		case BOTTLE_BEAUTY:
			window.mode = PICTURE_FRAME_BEAUTY;
			break;
		case PICTURE_FRAME_BEAUTY:
			window.mode = STILL_LIFE;
			break;
		case STILL_LIFE:
			window.mode = ORANGE_BEAUTY;
			break;
	}
}

void KeyboardFunc(unsigned char c, int x, int y)
{
	switch (c)
	{
	case 'w':
		window.wireframe = !window.wireframe;
		break;
	case 'd':
		window.draw_normals = !window.draw_normals;
		break;
	case 'm':
		SwitchModes();
		break;
	case 27:
	case 'x':
		glutLeaveMainLoop();
		return;
	case 's':
		window.SwitchWallpaper();
		break;
	}
}

void CloseFunc()
{
	// take down shaders
	shader.TakeDown();
	window.window_handle = (GLuint) -1;
}

void PassiveMouseFunc(int x, int y)
{
	y = window.height - y;
	window.x = x;
	window.y = y;
}



void ClickMouseFunc( int button, int state, int x , int y)
{
	y = window.height - y;
	if (button == GLUT_LEFT_BUTTON)
	{
		if (state == GLUT_DOWN)
		{
			window.UpdateSource(glm::vec2(x,y));
			window.UpdateDestination(glm::vec2(x,y));
		}

		if (state == GLUT_UP)
		{
			window.UpdateDestination(glm::vec2(x,y));
			window.destinationSet = true;

		}
	}

}

void MotionFunc(int x, int y)
{
	y = window.height - y;
	window.UpdateDestination(glm::vec2(x,y));
}

int main(int argc, char * argv[])
{
	glutInit(&argc , argv);
	ilInit();
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
	glutInitWindowPosition(0 , 0);
	glutInitWindowSize(window.width , window.height);
	window.window_handle = glutCreateWindow("Still Life");
	glutDisplayFunc(DisplayFunc);
	glutTimerFunc(1000 / 60, TimerFunc, 1000 / 60);
	glutReshapeFunc(ReshapeFunc);
	glutSpecialFunc(SpecialFunc);
	glutKeyboardFunc(KeyboardFunc);
	glutCloseFunc(CloseFunc);
	glutPassiveMotionFunc(PassiveMouseFunc);
	glutMotionFunc(MotionFunc);
	glutMouseFunc(ClickMouseFunc);
	glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);

	if (glewInit() != GLEW_OK)
	{
		cerr << "GLEW failed to initialize." << endl;
		return 0;
	}

	if (!window.fbo.Initialize(glm::ivec2(window.width, window.height), 3, false))
	{
		cerr << "Frame buffer failed to initialize." << endl;
		return 0;
	}

	WindowStruct mws;
	mws.grid_size1 = glm::ivec2(300, 300);
	mws.grid_size2 = glm::ivec2(300, 300);
	mws.function1 = Sphere;
	mws.function2 = Bottle;
	mws.open = false;
	window.PostGLInitialize((void *) &mws, window.mode);

	glutMainLoop();
	return 0;
}
